
#include "xdisk.h"
#include "xfat.h"

/*
 * xdisk_init
 * 
 * init disk driver \ name \ path
 * */
xfat_err_t xdisk_init(xdisk_t *disk, const char * name, xdisk_driver_t *driver, void *init_data)
{
    xfat_err_t err = FS_ERR_EOK;
    disk->driver = driver;
    memcpy(disk->name, name, strlen(name)>32 ? 32 : strlen(name));
    disk->path = init_data;
    return err;
}

/*
 * xdisk_read
 * 
 * 1. open disk
 * 2. read sector
 * 3. close disk
 * 
 * */
xfat_err_t xdisk_read(xdisk_t *disk, u8_t *buffer, u32_t start_sector, u32_t count)
{
    xfat_err_t err;

    err = disk->driver->open(disk, disk->path);
    if (err < 0)
    {
        return err;
    }
    
    if (start_sector + count >= disk->total_sector)
    {
        return FS_ERR_EPARAM;
    }

    err = disk->driver->read(disk, buffer, start_sector, count);
    if( err < 0)
    {
        disk->driver->close(disk);
        return err;
    }

    err = disk->driver->close(disk);
    return err;
}

/*
 * xdisk_read
 * 
 * 1. open disk
 * 2. write sector
 * 3. close disk
 * 
 * */
xfat_err_t xdisk_write(xdisk_t *disk, u8_t *buffer, u32_t start_sector, u32_t count)
{
    xfat_err_t err;

    err = disk->driver->open(disk, disk->path);
    if (err < 0)
    {
        return err;
    }
    
    if (start_sector + count >= disk->total_sector)
    {
        return FS_ERR_EPARAM;
    }

    err = disk->driver->write(disk, buffer, start_sector, count);
    if( err < 0)
    {
        disk->driver->close(disk);
        return err;
    }

    err = disk->driver->close(disk);
    return err;
}

/*
 * xdisk_extend_part_parse
 * 
 * 1. open disk
 * 2. read  first sector
 * 3. parse root mbr part info
 * 4. parse ext  mbr part info
 * 5. list  part to part_root
 * 
 * */
xfat_err_t xdisk_extend_part_parse(xdisk_t *disk, u32_t start_sector, xdisk_part_t * part_root)
{
    xfat_err_t err = FS_ERR_EOK;
    u8_t *read_buff = malloc(disk->sector_size + 1);
    mbr_part_t * mbr_part;
    u32_t ext_start_sector = start_sector;

    while (1)
    {
        err = xdisk_read(disk, read_buff, start_sector, 1);
        if (err != FS_ERR_EOK)
        {
            printf("xdisk extend part parse read first sector <%d> err <%d>\r\n", start_sector, err);
            return err;
        }

        mbr_part = ((mbr_t *)read_buff)->part_info;
        if (mbr_part->system_id == FS_NOT_VALID)
        {
            mbr_part++;
            start_sector = ext_start_sector + mbr_part->relative_sectors;
            continue;
        }

        xdisk_part_t * new_part = malloc(sizeof(xdisk_part_t));
        new_part->part_info = malloc(sizeof(mbr_part_t));
        new_part->part_info = mbr_part;
        new_part->type = mbr_part->system_id;
        new_part->start_sector = start_sector + mbr_part->relative_sectors;
        new_part->total_sector = mbr_part->total_sectors;
        new_part->disk      = disk;

        part_root->prev->next = new_part;
        new_part->prev        = part_root->prev;
        new_part->next  = part_root;
        part_root->prev = new_part;

        if ((++mbr_part)->system_id != FS_EXTEND)
        {
            err = FS_ERR_EOF;
            break;
        }

        start_sector = ext_start_sector + mbr_part->relative_sectors;
    }

    free(read_buff);
    return FS_ERR_EOK;
}
/*
 * xdisk_parse
 * 
 * 1. read  disk first sector
 * 2. parse root mbr part info
 * 3. parse ext  mbr part info
 * 4. list  part to part_root
 * 
 * */
xfat_err_t xdisk_parse(xdisk_t *disk, xdisk_part_t * part_root)
{
    xfat_err_t err = FS_ERR_EOK;
    u8_t *read_buff = malloc(disk->sector_size + 1);
    mbr_part_t * mbr_part;
        
    err = xdisk_read(disk, read_buff, 0, 1);
    if (err != FS_ERR_EOK)
    {
        printf("xdisk parse read first sector error\r\n");
        return err;
    }

    mbr_part = ((mbr_t *)read_buff)->part_info;

    for (int i = 0; i < 4; i++, mbr_part++)
    {
        if (mbr_part->system_id == FS_NOT_VALID)
        {
            continue;
        }
        
        if (mbr_part->system_id == FS_EXTEND)
        {
            xdisk_extend_part_parse(disk, mbr_part->relative_sectors, part_root);
            continue;
        }

        xdisk_part_t * new_part = malloc(sizeof(xdisk_part_t));
        new_part->part_info = malloc(sizeof(mbr_part_t));
        new_part->part_info = mbr_part;
        new_part->type = mbr_part->system_id;
        new_part->start_sector = mbr_part->relative_sectors;
        new_part->total_sector = mbr_part->total_sectors;
        new_part->disk      = disk;
        
        part_root->prev->next = new_part;
        new_part->prev        = part_root->prev;
        new_part->next  = part_root;
        part_root->prev = new_part;
    }
    
    free(read_buff);
    return FS_ERR_EOK;
}



